﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebDownloader
{
    public class QueueProcessor
    {
        public SortedList<Guid, System.Threading.Thread> mThreads = new SortedList<Guid, System.Threading.Thread>();
        public object mThreadsLock = new object();
        public List<ProcessItem> mMasterList = new List<ProcessItem>();
        public Queue<ProcessItem> mQueue = new Queue<ProcessItem>();
        public int mTotal = 0;
        public object mQueueLock = new object();
        public int mMaxThreads = 5;
        public bool mStop = false;
        private System.Threading.Thread mMainThread = null;
        private EventManager mEventManager = null;

        public QueueProcessor(bool pLoad, EventManager pEventManager)
        {
            mEventManager = pEventManager;
            if (pLoad) LoadQueue();
        }

        public class ProcessItem
        {
            public EventManager EventManager { get; set; }
            public Guid Key { get; set; }
            public string FileName { get; set; }
            public string URL { get; set; }
            public string DownloadID { get; set; }
            public bool Downloaded { get; set; }
        }

        public void QueueProcessItem(ProcessItem pProcessItem)
        {
            lock (mQueueLock)
            {
                mTotal++;
                mMasterList.Add(pProcessItem);
                mQueue.Enqueue(pProcessItem);
            }
        }

        public void SaveQueue()
        {
            lock (mQueueLock)
            {
                MaxFramework.Serialization.Serializer.WriteObjectToXmlFileASCII(mMasterList, "MasterList.xml");
            }
        }

        public void LoadQueue()
        {
            lock (mQueueLock)
            {
                if (System.IO.File.Exists("MasterList.xml"))
                {
                    mMasterList = MaxFramework.Serialization.Serializer.ReadObjectFromXmlFileASCII<List<ProcessItem>>("MasterList.xml", typeof(List<ProcessItem>));

                    mQueue.Clear();

                    foreach (var item in mMasterList)
                    {
                        item.EventManager = mEventManager;
                        if (System.IO.File.Exists(string.Format(@".\Completed\{0}", item.FileName)))
                            item.Downloaded = true;

                        if (!item.Downloaded) mQueue.Enqueue(item);
                    }
                }
            }
        }

        public void Start()
        {
            mMainThread = new System.Threading.Thread(new System.Threading.ThreadStart(ProcessInternal));
            mMainThread.Start();
        }

        public void Stop()
        {
            try
            {
                mStop = true;
                System.Threading.Thread.Sleep(4000);
                mMainThread.Abort();
            }
            catch { }
        }

        private void ProcessInternal()
        {
            while (true)
            {
                if (mStop) break;
                lock (mThreads)
                {
                    if (mThreads.Count < mMaxThreads)
                    {
                        lock (mQueueLock)
                        {
                            if (mQueue.Count > 0)
                            {
                                var tProcessItem = mQueue.Dequeue();
                                int tCurrent = mMasterList.Select(t => t.Downloaded == true).Count();
                                tProcessItem.EventManager.UpdateProgress(mMasterList.Count, tCurrent, tProcessItem.FileName);
                                var tThread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(DownloadFile));

                                mThreads.Add(tProcessItem.Key, tThread);
                                tThread.Start((object)tProcessItem);
                            }
                        }

                    }

                    System.Threading.Thread.Sleep(1000);

                }
            }
        }


        private void DownloadFile(object args)
        {
            var tProcessItem = (ProcessItem)args;

            tProcessItem.EventManager.UpdateStatusLog(tProcessItem.Key, string.Format("{0}: {1}", "Downloading...", tProcessItem.FileName));

            var message = Functions.DownloadFile(tProcessItem.URL, tProcessItem.FileName);

            if (message.Length > 0)
            {
                tProcessItem.EventManager.UpdateStatusLog(tProcessItem.Key, string.Format("{0}: {1}, Error: {2}", "FAILED!!!", tProcessItem.FileName, message));
            }
            else
            {
                tProcessItem.Downloaded = true;
                tProcessItem.EventManager.UpdateStatusLog(tProcessItem.Key, string.Format("{0}: {1}", "Completed!!!", tProcessItem.FileName));
            }
            lock (mThreadsLock)
            {
                mThreads.Remove(tProcessItem.Key);
            }
        }
    }
}
